﻿#include "LcdAudioSwitcherApplication.h"

#include <QtCore/QDebug>

QSharedMemory LcdAudioSwitcherApplication::sharedMem(SHARED_MEMORY_MESSAGE);

LcdAudioSwitcherApplication::LcdAudioSwitcherApplication(int argc, char *argv[], QString title)
	: QCoreApplication(argc,argv)
{
	as=NULL;
	lcd=NULL;
	firstLine=0;
	firstLineColor=0;
	exitCode=0;

	sharedMem.detach();

	HRESULT hr = CoInitialize(NULL);
	if (SUCCEEDED(hr))
	{
		as = new AudioSwitcher();
		lcd = new LogiLcd(title);
		updateScreen();


		timer = new QTimer();
		timer->setInterval(100);
		connect(timer, SIGNAL(timeout()), this, SLOT(timeout()));
		timer->start();

		connect(lcd, SIGNAL(buttonPressed(int)), this, SLOT(buttonPressed(int)));
	}
	else
	{
		exitCode=-1;
	}
}

LcdAudioSwitcherApplication::~LcdAudioSwitcherApplication()
{
	shutdown();
}
void LcdAudioSwitcherApplication::shutdown()
{
	if(lcd!=NULL)
	{
		disconnect(lcd, SIGNAL(buttonPressed(int)), this, SLOT(buttonPressed(int)));
		delete lcd;
	}
	lcd=NULL;
	if(as!=NULL)
		delete as;
	as=NULL;
}


void LcdAudioSwitcherApplication::buttonPressed(int button)
{
	if(button!=0)
	{
		if(button & LOGI_LCD_MONO_BUTTON_0)
		{
			nextAudio(eMultimedia);
		}
		if(button & LOGI_LCD_MONO_BUTTON_1)
		{
			nextAudio(eCommunications);
		}
		if(button & LOGI_LCD_MONO_BUTTON_2)
		{
		}
		if(button & LOGI_LCD_MONO_BUTTON_3)
		{
		}
		updateScreen();
	}
}

void LcdAudioSwitcherApplication::nextAudio(ERole role)
{
	if(!as) exit();
	as->SetDefaultNextAudioPlaybackDevice(role);
	if(role==eMultimedia)
		Beep(1000, 500);
	else Beep(2000, 500);
}

void LcdAudioSwitcherApplication::updateScreen()
{
	//qDebug()<<"updateScreen isInit "<<lcd->isInit;
	if(!as) exit();
	if(!lcd->isInit)
	{
		QTimer::singleShot(10000, Qt::VeryCoarseTimer, this, SLOT(updateScreen()));
		return;
	}

	lcd->SetColorTitle("Lcd Audio Switcher");

	QString console = as->GetDefaultAudioEndpoint(eConsole);
	QString multimedia = as->GetDefaultAudioEndpoint(eMultimedia);
	QString communications = as->GetDefaultAudioEndpoint(eCommunications);
	QMap<QString, QString> devices = as->GetAudioPlaybackDevices();

	QMapIterator<QString, QString> i(devices);
	int line=0;
	int lineMultimedia = 0;
	int lineCommunications = 0;
	int lineMultimediaColor = 0;
	int lineCommunicationsColor = 0;
	if(devices.size()==0)
		QTimer::singleShot(10000, Qt::VeryCoarseTimer, this, SLOT(updateScreen()));

	while (i.hasNext())
	{
		i.next();
		QString key = i.key();
		QString defaultDev("  ");
		if(key==multimedia)
		{
			lineMultimedia = line-firstLine;
			lineMultimediaColor = line-firstLineColor;
			if(key==communications)
			{
				lineCommunications = line-firstLine;
				lineCommunicationsColor = line-firstLineColor;
				defaultDev="**";
			}
			else defaultDev="* ";
		}
		else if(key==communications)
		{
			lineCommunications = line-firstLine;
			lineCommunicationsColor = line-firstLineColor;
			defaultDev=" *";
		}
		//qDebug()<<"device "+defaultDev+" : "+i.value();


		lcd->SetMonoText(line-firstLine,defaultDev+" "+i.value());
		lcd->SetColorText(line-firstLineColor,defaultDev+" "+i.value());
		++line;
	}
	if(line <= LOGI_LCD_MONO_MAX_LINE)
	{
		for(line;line-firstLine<=LOGI_LCD_MONO_MAX_LINE;++line)
		{
			lcd->SetMonoText(line-firstLine,"");
		}
	}

	if(lineMultimedia >= LOGI_LCD_MONO_MAX_LINE)
	{
		firstLine += lineMultimedia - (LOGI_LCD_MONO_MAX_LINE-1);
		updateScreen();
	}
	else if(lineMultimedia < 0)
	{
		firstLine += lineMultimedia;
		updateScreen();
	}
	else
	{
		int newFirstLine = firstLine;
		if(lineCommunications >= LOGI_LCD_MONO_MAX_LINE)
		{
			newFirstLine += lineCommunications - (LOGI_LCD_MONO_MAX_LINE-1);
		}
		else if(lineCommunications < 0)
		{
			newFirstLine += lineCommunications;
		}

		if(newFirstLine!=firstLine)
		{
			int diff = firstLine - newFirstLine;
			lineMultimedia += diff;
			if(lineMultimedia >= LOGI_LCD_MONO_MAX_LINE)
			{

				newFirstLine += lineMultimedia - (LOGI_LCD_MONO_MAX_LINE-1);
			}
			else if(lineMultimedia < 0)
			{
				newFirstLine += lineMultimedia;
			}

			if(newFirstLine!=firstLine)
			{
				firstLine = newFirstLine;
				updateScreen();
			}
		}
	}

	lcd->SetMonoText(LOGI_LCD_MONO_MAX_LINE,"  *      *");
	lcd->SetColorText(LOGI_LCD_COLOR_MAX_LINE,"TODO");
}

bool LcdAudioSwitcherApplication::loadIntoSharedMem(QString message)
{
	//qDebug()<<"loadIntoSharedMem " <<message;
	// First, test whether a shared memory segment is already attached to the process.
	// If so, detach it
	if (sharedMem.isAttached())
	{
		//qDebug()<<"detach " <<sharedMem.detach();
		sharedMem.detach();
	}
	QBuffer buffer;
	buffer.open( QBuffer::ReadWrite );
	QDataStream out( &buffer );
	out << message;
	int size = buffer.size();
	if ( !sharedMem.create( size ) ) 
	{
		qDebug()<<"sharedMem.create("<<size<<") fail ";
		return false;
	}
	// Write into the shared memory
	sharedMem.lock();
	char *to = (char*)sharedMem.data();
	const char *from = buffer.data().data();
	memcpy( to, from, qMin( sharedMem.size(), size ) );
	sharedMem.unlock();
	Sleep(200);
	return true;
}

QString LcdAudioSwitcherApplication::loadFromSharedMem()
{
	//qDebug()<<"loadFromSharedMem ";
	QString message;
	if (!sharedMem.attach()) 
	{
		//qDebug()<<"isAttached "<<sharedMem.isAttached();
		//If an attempt of reading from the shared memory before data is written
		return message;
	}
	QBuffer buffer;
	QDataStream in(&buffer);
	QString text;
	sharedMem.lock();
	buffer.setData((char*)sharedMem.constData(), sharedMem.size());
	buffer.open(QBuffer::ReadOnly);
	in >> message;
	//qDebug()<<"message " <<message;
	sharedMem.unlock();
	// As this is the last process attached to the shared memory segment
	// the shared memory segment is released, destroying its contents
	sharedMem.detach();
	return message;
}


void LcdAudioSwitcherApplication::timeout()
{
	QString message = loadFromSharedMem();
	if(message=="refresh")
	{
		updateScreen();
	}
	else if(message=="next" || message=="next_multimedia")
	{
		nextAudio(eMultimedia);
		updateScreen();
	}
	else if(message=="next" || message=="next_communications")
	{
		nextAudio(eCommunications);
		updateScreen();
	}
}